package deposit.main;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class DaysNumber {
    public static final int LEAP_YEAR = 366;
    public static final int COMMON_YEAR = 365;

    private DaysNumber() {
    }

    public static int daysInDepositYear(Date data) {
	GregorianCalendar calendar = new GregorianCalendar();
	calendar.setTime(data);
	GregorianCalendar yearEnd = new GregorianCalendar(calendar.get(Calendar.YEAR), Calendar.DECEMBER, 31);
	int ret = yearEnd.get(Calendar.DAY_OF_YEAR)- calendar.get(Calendar.DAY_OF_YEAR);
	calendar.add(GregorianCalendar.YEAR, 1);
	ret += calendar.get(Calendar.DAY_OF_YEAR);
	return ret;
    }

    public static int getDays(Date start, Date end) {
	// проверка на правильность вводимых данных
	if (isIncorrectArgs(start, end)) {
	    throw new IllegalArgumentException(
		    "Start date must be before the end date!");
	}

	// проверка на то, находятся ли даты в одном году
	if (isLocatedInSameYear(start, end)) {
	    int startsDaysFromBeginningYear = daysFromBeginningYear(start);
	    int endDaysFromBeginningYear = daysFromBeginningYear(end);
	    return endDaysFromBeginningYear - startsDaysFromBeginningYear;
	}

	int daysBeforeEndYearToStartDate = daysBeforeEndYear(start);
	int daysFromBeginningYearToEndDate = daysFromBeginningYear(end);

	// проверка промежуточных годов
	int differenceYears = getDifferenceYears(start, end);
	Calendar calendar = GregorianCalendar.getInstance();
	calendar.setTime(start);
	int allDays = 0;
	for (int i = 0; i < differenceYears - 1; i++) {
	    calendar.add(GregorianCalendar.YEAR, 1);

	    int year = calendar.get(GregorianCalendar.YEAR);
	    GregorianCalendar gc = (GregorianCalendar) calendar;

	    if (gc.isLeapYear(year)) {
		allDays += LEAP_YEAR;
	    } else
		allDays += COMMON_YEAR;
	}

	// склейка крайних дней
	allDays += daysBeforeEndYearToStartDate
		+ daysFromBeginningYearToEndDate + 1;
	return allDays;
    }

    public static int daysBeforeEndYear(Date date) {
	Calendar calendar = new GregorianCalendar();
	calendar.setTime(date);
	Calendar yearEnd = new GregorianCalendar(calendar.get(Calendar.YEAR),
		Calendar.DECEMBER, 31);
	return yearEnd.get(Calendar.DAY_OF_YEAR)
		- calendar.get(Calendar.DAY_OF_YEAR);
    }

    public static int daysFromBeginningYear(Date date) {
	Calendar calendar = new GregorianCalendar();
	calendar.setTime(date);
	Calendar yearStart = new GregorianCalendar(calendar.get(Calendar.YEAR),
		Calendar.JANUARY, 1);
	return calendar.get(Calendar.DAY_OF_YEAR)
		- yearStart.get(Calendar.DAY_OF_YEAR);
    }

    public static boolean isLocatedInSameYear(Date date1, Date date2) {
	Calendar calendar = new GregorianCalendar();
	calendar.setTime(date1);
	int year1 = calendar.get(Calendar.YEAR);
	calendar.setTime(date2);
	int year2 = calendar.get(Calendar.YEAR);
	if (year1 == year2) {
	    return true;
	}
	return false;
    }

    public static boolean isLeapYear(Date date) {
	GregorianCalendar gc = new GregorianCalendar(date.getYear(),
		date.getMonth(), date.getDay());
	if (gc.isLeapYear(gc.get(Calendar.YEAR))) {
	    return true;
	}
	return false;
    }

    private static boolean isIncorrectArgs(Date start, Date end) {
	Calendar calendar = GregorianCalendar.getInstance();
	calendar.setTime(start);
	long startDate = calendar.getTimeInMillis();
	calendar.setTime(end);
	long endDate = calendar.getTimeInMillis();
	if (startDate > endDate) {
	    return true;
	}
	return false;
    }

    private static int getDifferenceYears(Date start, Date end) {
	Calendar calendar = GregorianCalendar.getInstance();
	calendar.setTime(start);
	int startYear = calendar.get(Calendar.YEAR);
	calendar.setTime(end);
	int endYear = calendar.get(Calendar.YEAR);
	calendar.setTime(start);
	return endYear - startYear;
    }
}
